﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Kokomo.Mirror.Ia32
{
	public class ExtendedOpCodeGroup
	{
		public ExtendedOpCodeGroup(params ExtendedOpCode[] entries)
		{
			this.OperandTypesByOpCode = new Dictionary<int, OperandType[]>();
			//this.MnemonicsByExtension = new Dictionary<int, Mnemonic>();
			this.Entries = entries;
		}

		public Dictionary<int, OperandType[]> OperandTypesByOpCode { get; private set; }
		//public Dictionary<int, Mnemonic> MnemonicsByExtension { get; private set; }
		public ExtendedOpCode[] Entries { get; private set; }

		private ExtendedOpCode? GetExtendedOpCode(ModRM modrm, Prefixes prefixes)
		{
			foreach (var entry in this.Entries)
			{
				bool itMatches =
					(entry.ModRM.Reg == modrm.Reg)
					&& (!entry.HasMod || entry.ModRM.Mod == modrm.Mod)
					&& (!entry.HasRM || entry.ModRM.RM == modrm.RM)
					&& ((entry.MandatoryPrefixes & prefixes) == entry.MandatoryPrefixes)
					;
				if (itMatches) return entry;
			}

			return null;
		}

		public bool HasOpCodeExtensionPair(
			int value,
			ModRM modrm,
			Prefixes prefixes
			)
		{
			bool hasIt =
				this.OperandTypesByOpCode.ContainsKey(value)
				&& this.GetExtendedOpCode(modrm, prefixes).HasValue
				;
			return hasIt;
		}
		public OpCode GetOpCode(
			int value,
			ModRM modRM,
			Prefixes prefixes
			)
		{
			ExtendedOpCode? extension = this.GetExtendedOpCode(modRM, prefixes);

			if (!extension.HasValue) throw new ArgumentException("This group does not contain the opcode / extension pair");

			OperandType[] operandTypes = this.OperandTypesByOpCode[value];

			OpCode opcode = new OpCode(value, 1, OpCodeForm.RegExtension, extension.Value.Mnemonic, operandTypes);
			return opcode;
		}
	}
}
